package com.sunsharing.transport.api;

import com.sunsharing.common.*;
import com.sunsharing.common.loadbalance.RandomLoadBalance;
import com.sunsharing.common.utils.StringUtils;
import com.sunsharing.transport.Channel;
import com.sunsharing.transport.ClientCreater;
import com.sunsharing.transport.ConnectClients;
import com.sunsharing.transport.HeartDect;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.FileInputStream;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created with IntelliJ IDEA.
 * User: criss
 * Date: 13-4-11
 * Time: 上午10:20
 * To change this template use File | Settings | File Templates.
 */
public class Send {

    static Logger logger = Logger.getLogger(Send.class);

    //配置URL的值
    static List<URL> lists = new ArrayList<URL>();

    static Lock lock =  new ReentrantLock();

    static ClientHandle clientHandle = new ClientHandle();

    ArrayBlockingQueue<Context> c = new ArrayBlockingQueue(1);

    void addResult(Context context)
    {
        c.add(context);
    }

    public  String synRequest(String msg)
    {
        Context context = ContextCreate.createRequestContext(msg);
        lock.lock();
        try
        {
            if(ConnectClients.activeClients.size()==0)
            {
                //初始化节点
                initConfig();
                if(lists.size()==0)
                {
                    throw new RuntimeException("没有配置连接服务端");
                }
                tryConnect();
            }
        }catch (Exception e)
        {
            logger.error("初始化连接出错",e);
            throw new RuntimeException("初始化连接失败");
        }finally {
            lock.unlock();
        }
        //连接完成
        List<Channel> activeClients = new ArrayList<Channel>();
        for(Channel ch:ConnectClients.activeClients)
        {
            if(!ch.isclose())
            {
                activeClients.add(ch);
            }
        }
        if(activeClients.size()==0)
        {
            throw new RuntimeException("连接失败没有活跃的连接");
        }

        logger.info("开始发送....");
        LoadBalance loadBalance = new RandomLoadBalance();
        int index = loadBalance.getIndex(activeClients.size());

        clientHandle.addListener(context.getTaskId(),this);
        try{
            Channel ch = activeClients.get(index);
            context.setApiNode(ch.url.getMyNodeId());
            context.setBeginNode(ch.url.getToNodeId());
            ch.send(context);
            Context con = c.poll(30,TimeUnit.SECONDS);
            if(con==null)
            {
                throw new RuntimeException("接收到结果报文出错");
            }
            //logger.info("收到报文:"+con.getMsg().msg);
            con.printHistory();
            return con.getMsg().msg;
        }catch (Exception e2)
        {
            logger.error("发送和结果处理出错",e2);
            throw new RuntimeException("发送和结果处理出错");
        } finally {
            clientHandle.removeListener(context.getTaskId());
        }
    }
    //初始化目录
    private static void initConfig()
    {
        if(lists.size()>0)
        {
            return;
        }

        FileInputStream input = null;
        try
        {
            InetAddress addr = InetAddress.getLocalHost();
            String ip=addr.getHostAddress().toString();//获得本机IP

            String path = StringUtils.getClassPath();
            String requesPath = path+ "api.xml";

            input  = new FileInputStream(requesPath);
            byte[] buffer = new byte[1024];
            int len = 0;
            String xml = "";
            while((len=input.read(buffer))!=-1)
            {
                xml += new String(buffer,0,len);
            }
            Document doc = DocumentHelper.parseText(xml);
            Element water = doc.getRootElement();

            List<Element> eles = water.elements("channel");
            Element apiNode = water.element("api_id");
            int i = 0;
            for(Element ele:eles)
            {
               String url = ele.attributeValue("url");
               if(url.indexOf("?")==-1)
               {
                   url += "?"+ Constant.URL_PAR_MY_NODE_ID+"="+apiNode.getText()+"&"+
                           Constant.URL_PAR_BYCLIENT+"=true";
               }else
               {
                   url += "&"+ Constant.URL_PAR_MY_NODE_ID+"="+apiNode.getText()+"&"+
                           Constant.URL_PAR_BYCLIENT+"=true";
               }
               lists.add(URL.valueOf(url));
            }
        }catch(Exception e)
        {
            logger.error("初始化Socket客户端出错",e);
        }
    }

    private static void tryConnect()
    {
         ClientCreater client = new ClientCreater();
         int total = lists.size();
         int error = 0;
         for(URL url:lists)
         {
             try{
                client.createClient(url).connect(url,clientHandle);
             }catch (Exception e)
             {
                 logger.error("连接"+url+"出错!!!!!",e);
                 error++;
             }
         }
         if(error==total)
         {
             throw new RuntimeException("无法连接到服务端");
         }

        ExecutorService executor = Executors.newSingleThreadExecutor();
        ConnectClients.watch();
        FutureTask<Integer> future =
                new FutureTask<Integer>(new Callable<Integer>()
                {
                //使用Callable接口作为构造参数
                    public Integer call() {
                        //真正的任务在这里执行，这里的返回值类型为String，可以为任意类型
                        long start = new Date().getTime();
                        while(true)
                        {
                            if(ConnectClients.activeClients.size()>0)
                            {
                                return ConnectClients.activeClients.size();
                            }

                            long end = new Date().getTime();

                            if(end-start>=5000)
                            {
                                return 0;
                            }
                            try{
                                Thread.sleep(200);
                            }catch (Exception e)
                            {

                            }
                        }

                    }
                });
        executor.execute(future);
        int result = 0;
        try {
            result = future.get(8000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            future.cancel(true);
        } catch (ExecutionException e) {
            future.cancel(true);
        } catch (TimeoutException e) {
            future.cancel(true);
        } finally {
            executor.shutdown();
        }
        if(result == 0 )
        {
            throw new RuntimeException("无法连接到服务端");
        }
    }



}
